/*
 *  ErrorManager.cpp
 *
 *  O gerenciador de erros recebe como parametro o erro (codigo int) e a linha para disparar
 *  uma mensagem de erro.
 */

#include <stdio.h>
#include <stdlib.h>
#include "ErrorManager.h"
#include "analex.h"

unsigned int Num_Error = 0;

void ErrorMessage(int error, int line) {
    switch (error) {
        case INVALID_CARACTER: fprintf(stderr, "** ERRO LEXICO: Caractere invalido na linha %d. \n", line);
            Num_Error++;
            break;

        case INVALID_NUMBER: fprintf(stderr, "** ERRO LEXICO: Numero invalido na linha %d. \n", line);
            Num_Error++;
            break;

        case UNEXPECTED_COMMENTARY_END: fprintf(stderr, "** ERRO LEXICO: Fim de comentario inesperado na linha %d. \n", line);
            Num_Error++;
            break;

        case UNEXPECTED_EOF_COMMENTARY: fprintf(stderr, "** ERRO LEXICO: Fim de arquivo inesperado, esperava-se fim de comentario. \n");
            Num_Error++;
            break;

        case UNEXPECTED_EOF_LITERAL: fprintf(stderr, "** ERRO LEXICO: Fim de arquivo inesperado, esperava-se fim de literal. \n");
            Num_Error++;
            break;

        case MEMORY_OVERFLOW: fprintf(stderr, "** ERRO LEXICO: Estouro de memoria. \n");
            Num_Error++;
            break;

        case FILE_NOT_FOUND: fprintf(stderr, "** ERRO LEXICO: Arquivo fornecido nao encontrado. \n");
            Num_Error++;
            break;

        case EXTEND_OR_BRACE_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se os tokens 'extends' ou '{'. na linha %d.\n", line);
            Num_Error++;
            break;

        case STATIC_OR_TYPE_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se o tipo de retorno do metodo na linha %d.\n", line);
            Num_Error++;
            break;

        case METHOD_NAME_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se o nome do metodo na linha %d.\n", line);
            Num_Error++;
            break;

        case LBRACKET_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se a abertura do colchete na linha %d.\n", line);
            Num_Error++;
            break;

        case RBRACE_METHOD_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se fechar as chaves do metodo na linha %d.\n", line);
            Num_Error++;
            break;

        case RBRACE_CLASS_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se fechar as chaves da classe na linha %d.\n", line);
            Num_Error++;
            break;

        case RBRACE_IF_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se fechar as chaves na linha %d.\n", line);
            Num_Error++;
            break;

        case RBRACE_WHILE_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se fechar as chaves do while na linha %d.\n", line);
            Num_Error++;
            break;

        case SEMICOLON_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se o ';' do fim da instrucao na linha %d.\n", line);
            Num_Error++;
            break;

        case LPARENT_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se a abertura de parenteses na linha %d.\n", line);
            Num_Error++;
            break;

        case RPARENT_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se o fechamento de parenteses na linha %d.\n", line);
            Num_Error++;
            break;

        case INVALID_EXPRESSION: fprintf(stderr, "** ERRO SINTATICO: Expressao invalida. Linha: %d.\n", line);
            Num_Error++;
            break;

        case TYPE_EXPECTED: fprintf(stderr, "** ERRO SINTATICO: Esperava-se um tipo na linha %d.\n", line);
            Num_Error++;
            break;

        case INVALID_STATEMENT: fprintf(stderr, "** ERRO SINTATICO: Comando invalido. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INVALID_INSTANCING: fprintf(stderr, "** ERRO SINTATICO: Construcao de objeto invalida. Linha: %d.\n", line);
            Num_Error++;
            break;

        case UNDECLARED_VAR: fprintf(stderr, "**ERRO SEMANTICO: Variavel utilizada mas nao declarada. Linha: %d.\n", line);
            Num_Error++;
            break;

        case VAR_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Variavel ja declarada anteriormente neste escopo. Linha: %d.\n", line);
            Num_Error++;
            break;

        case CLASS_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Classe ja declarada anteriormente. Linha: %d.\n", line);
            Num_Error++;
            break;

        case UNDECLARED_METHOD: fprintf(stderr, "**ERRO SEMANTICO: Metodo utilizado mas nao declarado. Linha: %d.\n", line);
            Num_Error++;
            break;

        case METHOD_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Encontrado metodo com a mesma assinatura ja declarado anteriormente. Linha: %d.\n", line);
            Num_Error++;
            break;

        case UNDECLARED_CLASS: fprintf(stderr, "**ERRO SEMANTICO: Classe utilizada mas nao encontrada. Linha: %d.\n", line);
            Num_Error++;
            break;

        case PARAMETER_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Parametro ja definido anteriormente. Linha: %d.\n", line);
            Num_Error++;
            break;

        case ATTRIBUTE_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Atributo ja definido anteriormente. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INCOMPATIBLE_TYPES: fprintf(stderr, "**ERRO SEMANTICO: Tipos incompativeis na expressao. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INCOMPATIBLE_TYPES_RETURN: fprintf(stderr, "**ERRO SEMANTICO: Tipo de retorno incompativel. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INCOMPATIBLE_TYPES_ASSIGN: fprintf(stderr, "**ERRO SEMANTICO: O tipo da expressao de atribuicao e incompativel com o tipo da variavel de destino. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INCOMPATIBLE_TYPES_LOOP: fprintf(stderr, "**ERRO SEMANTICO: Esperava-se uma expressao logica para a condicao de loop. Linha: %d.\n", line);
            Num_Error++;
            break;

        case BAD_USE_LENGTH: fprintf(stderr, "**ERRO SEMANTICO: Operador 'length' so deve ser aplicado em variaveis do tipo array. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INVALID_EXPRESSION_IDX: fprintf(stderr, "**ERRO SEMANTICO: Indice de acesso ao vetor invalido. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INVALID_NAME: fprintf(stderr, "**ERRO SEMANTICO: Declaracao incoerente. Linha: %d.\n", line);
            Num_Error++;
            break;

        case MAIN_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Foram encontradas mais de uma definicao do metodo principal(main).\n");
            Num_Error++;
            break;

        case MAIN_NOT_EXISTS: fprintf(stderr, "**ERRO SEMANTICO: Impossivel encontrar uma definicao do metodo pricipal(main).\n");
            Num_Error++;
            break;

        case INVALID_READ_EXPRESSION: fprintf(stderr, "**ERRO SEMANTICO: Tipo invalido para leitura com metodo 'read'. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INVALID_PRINT_EXPRESSION: fprintf(stderr, "**ERRO SEMANTICO: Tipo invalido para impressao. Linha: %d.\n", line);
            Num_Error++;
            break;

        case INVALID_ARRAY_LENGTH: fprintf(stderr, "**ERRO SEMANTICO: Expressao invalida para definicao do tamanho do arranjo. Linha: %d.\n", line);
            Num_Error++;
            break;

        case VECTOR_OPERATION: fprintf(stderr, "**ERRO SEMANTICO: Impossivel realizar operacoes entre vetores. Linha: %d.\n", line);
            Num_Error++;
            break;

        case AUSENT_RETURN: fprintf(stderr, "**ERRO SEMANTICO: Retorno do metodo nao encontrado. Linha: %d.\n", line);
            Num_Error++;
            break;

        case UNDEFINED_VARIABLE: fprintf(stderr, "**ERRO SEMANTICO: Variavel utilizada mas nao definida. Linha: %d.\n", line);
            Num_Error++;
            break;
    }

    return;
}

void ErrorMessage(int line, int token, int expected) {
    Num_Error++;
    fprintf(stderr, "** ERRO SINTATICO: Esperava-se o token ");
    printToken(expected);
    fprintf(stderr, ", mas foi encontrado o token ");
    printToken(token);
    fprintf(stderr, " na linha %d.\n", line);
}

void ErrorMessage(){
    fprintf(stderr, "\n**ERRO: Foram encontrados erros no codigo. Impossivel continuar a compilacao.\n\n");
}

unsigned int getNum_Error(){
    return Num_Error;
}
